package com.cs797.project;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import android.app.Activity;
import android.os.Bundle;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.view.View.OnClickListener;
import android.telephony.*;
import android.telephony.gsm.GsmCellLocation;
import android.telephony.cdma.CdmaCellLocation;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;

public class HotSpotterActivity extends Activity implements OnClickListener {

    private static final String TAG = "HotSpotter";

    String gsmLocationLookupURL = "http://cellphonetrackers.org/gsm/gsm-tracker.php";

    TelephonyManager tm;
    MyPhoneStateListener myListener;
    CellLocation cellLocation;
    LocationManager locationManager;
    HotSpotDataAdapter hotSpotAdapter;
    Criteria crta;
    String provider;
    String networkOperator;
    String gsmCdmaMCC;
    String gsmMNC;
    int gsmLAC = -1;
    int gsmCID = -1;
    int cdmaSID = -1;
    int cdmaBDID = -1;
    int cdmaNetworkID = -1;
    int phoneType;
    int signaldBm = 99;
    int userLong = -1;
    int userLat = -1;
    double towerLatitude = -1;
    double towerLongitude = -1;
    double msLatitude = -1;
    double msLongitude = -1;

    TextView txtCellLocation;
    TextView txtMCC;
    TextView txtGsmMNCCdmaSID;
    TextView txtGsmLacCdmaNetworkID;
    TextView txtGsmCIDCdmaBSID;
    TextView txtSignalStrengths;
    TextView txtTowerLatitude;
    TextView txtTowerLongitude;
    TextView txtUserLongitude;
    TextView txtUserLatitude;
    View btnTakeReading;
    View btnShowReadings;
    View btnDeleteData;
    View btnPopulateData;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        String context = Context.LOCATION_SERVICE;

        hotSpotAdapter = new HotSpotDataAdapter(this);
        hotSpotAdapter.open();

        txtCellLocation = (TextView) findViewById(R.id.celllocation);
        txtMCC = (TextView) findViewById(R.id.mcc);
        txtGsmMNCCdmaSID = (TextView) findViewById(R.id.gsmmnccdmasid);
        txtGsmLacCdmaNetworkID = (TextView) findViewById(R.id.gsmlaccdmanetworkid);
        txtGsmCIDCdmaBSID = (TextView) findViewById(R.id.gsmcidcdmabsid);
        txtSignalStrengths = (TextView) findViewById(R.id.signalstrengths);
        txtTowerLatitude = (TextView) findViewById(R.id.towerlat);
        txtTowerLongitude = (TextView) findViewById(R.id.towerlon);
        txtUserLongitude = (TextView) findViewById(R.id.phonelon);
        txtUserLatitude = (TextView) findViewById(R.id.phonelat);
        btnTakeReading = findViewById(R.id.btn_take_reading);
        btnShowReadings = findViewById(R.id.btn_show_readings);
        btnDeleteData = findViewById(R.id.btn_delete_data);
        btnPopulateData = findViewById(R.id.btn_populate_data);

        btnTakeReading.setOnClickListener(this);
        btnShowReadings.setOnClickListener(this);
        btnDeleteData.setOnClickListener(this);
        btnPopulateData.setOnClickListener(this);

        locationManager = (LocationManager) getSystemService(context);

        crta = new Criteria();
        crta.setAccuracy(Criteria.ACCURACY_FINE);
        crta.setAltitudeRequired(false);
        crta.setBearingRequired(false);
        crta.setCostAllowed(true);
        crta.setPowerRequirement(Criteria.POWER_LOW);
        provider = locationManager.getBestProvider(crta, true);

        // Location location = locationManager.getLastKnownLocation(provider);
        // displayLocation(location);

        txtUserLongitude.setText("MS Longitude: Not Yet Set");
        txtUserLatitude.setText("MS Latitude: Not Yet Set");

        // retrieve a reference to an instance of TelephonyManager
        myListener = new MyPhoneStateListener();
        tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        phoneType = tm.getPhoneType();
        Log.d(TAG, "Got phone tpye of: " + String.valueOf(phoneType));

        networkOperator = tm.getNetworkOperator();
        gsmCdmaMCC = networkOperator.substring(0, 3);

        txtMCC.setText("MCC: " + gsmCdmaMCC);

        switch (phoneType) {
        case TelephonyManager.PHONE_TYPE_GSM:
            cellLocation = (GsmCellLocation) tm.getCellLocation();
            gsmMNC = networkOperator.substring(3);
            gsmLAC = ((GsmCellLocation) cellLocation).getLac();
            gsmCID = ((GsmCellLocation) cellLocation).getCid();

            txtCellLocation.setText(((GsmCellLocation) cellLocation).toString());
            txtGsmMNCCdmaSID.setText("MNC: " + gsmMNC);
            txtGsmLacCdmaNetworkID.setText("LAC: " + String.valueOf(gsmLAC));
            txtGsmCIDCdmaBSID.setText("CID: " + String.valueOf(gsmCID));
            break;
        case TelephonyManager.PHONE_TYPE_CDMA:
            cellLocation = (CdmaCellLocation) tm.getCellLocation();
            cdmaSID = ((CdmaCellLocation) cellLocation).getSystemId();
            cdmaNetworkID = ((CdmaCellLocation) cellLocation).getNetworkId();
            cdmaBDID = ((CdmaCellLocation) cellLocation).getBaseStationId();

            txtCellLocation.setText(((CdmaCellLocation) cellLocation).toString());
            txtGsmMNCCdmaSID.setText("SID: " + String.valueOf(cdmaSID));
            txtGsmLacCdmaNetworkID.setText("Network ID: " + String.valueOf(cdmaNetworkID));
            txtGsmCIDCdmaBSID.setText("BID: " + String.valueOf(cdmaBDID));
            break;
        }

        txtSignalStrengths.setText("dBm: Not Yet Set");

        Log.d(TAG, "Setting listener...");
    }

    public void displayLocation() {
        DecimalFormat df = new DecimalFormat("#.######");

        txtUserLongitude.setText("MS Longitude: " + df.format(msLatitude));
        txtUserLatitude.setText("MS Latitude: " + df.format(msLongitude));
    }

    private final LocationListener locationListener = new LocationListener() {

        public void onLocationChanged(Location location) {
            msLatitude = location.getLatitude();
            msLongitude = location.getLongitude();
            displayLocation();
        }

        public void onProviderDisabled(String provider) {
            msLatitude = -2;
            msLongitude = -2;
            displayLocation();
        }

        public void onProviderEnabled(String provider) {
        }

        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

    };

    @Override
    protected void onPause() {
        super.onPause();
        tm.listen(myListener, PhoneStateListener.LISTEN_NONE);
        locationManager.removeUpdates(locationListener);
        Log.d(TAG, "Paused listener...");
    }

    @Override
    protected void onResume() {
        super.onResume();
        locationManager.requestLocationUpdates(provider, 1000, 0, locationListener);
        tm.listen(myListener, PhoneStateListener.LISTEN_CELL_LOCATION | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
        Log.d(TAG, "Resumed listener...");
    }

    public void locateGsmTower() throws Exception {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(gsmLocationLookupURL);

        try {
            List<NameValuePair> nvPairs = new ArrayList<NameValuePair>(1);
            nvPairs.add(new BasicNameValuePair("mcc", gsmCdmaMCC));
            nvPairs.add(new BasicNameValuePair("mnc", gsmMNC));
            nvPairs.add(new BasicNameValuePair("lac", String.valueOf(gsmLAC)));
            nvPairs.add(new BasicNameValuePair("cid", String.valueOf(gsmCID)));

            httpPost.setEntity(new UrlEncodedFormEntity(nvPairs));

            HttpResponse httpResponse = httpClient.execute(httpPost);

            String response = EntityUtils.toString(httpResponse.getEntity());
            Log.d(TAG, response);

            String pattern = "<a href='http://maps\\.google\\.com/maps.+ target='_black'>Lat=([0-9.\\-]+) Lon=([0-9.\\-]+)</a>";

            Pattern r = Pattern.compile(pattern);
            Matcher m = r.matcher(response);
            if (m.find()) {
                Log.d(TAG, "Got match: " + m.group(0));
                Log.d(TAG, "Got lat: " + m.group(1));
                Log.d(TAG, "Got lon: " + m.group(2));

                towerLatitude = Double.parseDouble(m.group(1));
                towerLongitude = Double.parseDouble(m.group(2));
            } else {
                towerLatitude = -2;
                towerLongitude = -2;
            }

            Log.d(TAG, "Got latitude: " + String.valueOf(towerLatitude));
            Log.d(TAG, "Got longitude: " + String.valueOf(towerLongitude));
        } catch (Exception e) {
            towerLatitude = -3;
            towerLongitude = -3;
            Log.d(TAG, e.getMessage());
        }
    }

    private void locateCdmaTower() {
        towerLatitude = ((CdmaCellLocation) cellLocation).getBaseStationLatitude();
        towerLongitude = ((CdmaCellLocation) cellLocation).getBaseStationLongitude();
        Log.d(TAG, "Updating CDMA BS Lat/Lon");
    }

    public void setBSLongitudeLatitude() {
        switch (phoneType) {
        case TelephonyManager.PHONE_TYPE_GSM:
            try {
                locateGsmTower();
            } catch (Exception e) {
                Log.d(TAG, e.getMessage());
                towerLatitude = -4;
                towerLongitude = -4;
            }
            break;
        case TelephonyManager.PHONE_TYPE_CDMA:
            locateCdmaTower();
            break;
        }
    }

    private class MyPhoneStateListener extends PhoneStateListener {
        @Override
        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
            Log.d(TAG, "Signal Strengths changed...");
            switch (phoneType) {
            case TelephonyManager.PHONE_TYPE_GSM:
                signaldBm = (-113 + (signalStrength.getGsmSignalStrength() * 2));
                break;
            case TelephonyManager.PHONE_TYPE_CDMA:
                signaldBm = signalStrength.getCdmaDbm();
                break;
            default:
                signaldBm = 42;
            }

            txtSignalStrengths.setText("Signal: " + String.valueOf(signaldBm) + " dBm");
        }

        @Override
        public void onCellLocationChanged(CellLocation cl) {
            Log.d(TAG, "Cell Location changed...");
            cellLocation = cl;
            switch (phoneType) {
            case TelephonyManager.PHONE_TYPE_GSM:
                networkOperator = tm.getNetworkOperator();
                Log.d(TAG, "Got network operator string: " + networkOperator);
                gsmMNC = networkOperator.substring(3);
                gsmLAC = ((GsmCellLocation) cellLocation).getLac();
                gsmCID = ((GsmCellLocation) cellLocation).getCid();

                txtCellLocation.setText(((GsmCellLocation) cellLocation).toString());
                txtGsmMNCCdmaSID.setText("MNC: " + gsmMNC);
                txtGsmLacCdmaNetworkID.setText("LAC: " + String.valueOf(gsmLAC));
                txtGsmCIDCdmaBSID.setText("CID: " + String.valueOf(gsmCID));
                break;
            case TelephonyManager.PHONE_TYPE_CDMA:
                cdmaSID = ((CdmaCellLocation) cellLocation).getSystemId();
                cdmaNetworkID = ((CdmaCellLocation) cellLocation).getNetworkId();
                cdmaBDID = ((CdmaCellLocation) cellLocation).getBaseStationId();

                txtCellLocation.setText(((CdmaCellLocation) cellLocation).toString());
                txtGsmMNCCdmaSID.setText("SID: " + String.valueOf(cdmaSID));
                txtGsmLacCdmaNetworkID.setText("Network ID: " + String.valueOf(cdmaNetworkID));
                txtGsmCIDCdmaBSID.setText("BID: " + String.valueOf(cdmaBDID));
                break;
            }

            setBSLongitudeLatitude();

            DecimalFormat df = new DecimalFormat("#.######");

            txtTowerLatitude.setText("Lat: " + df.format(towerLatitude));
            txtTowerLongitude.setText("Lon: " + df.format(towerLongitude));
        }
    }

    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btn_take_reading:
            Log.d(TAG, "Pressed take reading button");

            // towerLatitude = 39.128062;
            // towerLongitude = -84.432366;
            // msLatitude = 39.132721;
            // msLongitude = -84.429690;

            if ((towerLatitude < 0 && towerLatitude > -5) || (towerLongitude < 0 && towerLongitude > -5)) {
                Toast.makeText(getApplicationContext(), "Failed to obtain BS location", Toast.LENGTH_SHORT).show();
            } else if ((msLatitude < 0 && msLatitude > -5) || (msLongitude < 0 && msLongitude > -5)) {
                Toast.makeText(getApplicationContext(), "Failed to obtain MS location", Toast.LENGTH_SHORT).show();
            } else {
                try {
                    Bundle bundle = new Bundle(5);
                    bundle.putBoolean("current_position_only", true);
                    bundle.putDouble("towerLatitude", towerLatitude);
                    bundle.putDouble("towerLongitude", towerLongitude);
                    bundle.putDouble("msLatitude", msLatitude);
                    bundle.putDouble("msLongitude", msLongitude);

                    hotSpotAdapter.addMSInfo(gsmCdmaMCC, gsmMNC, gsmLAC, gsmCID, phoneType, towerLatitude,
                            towerLongitude, msLatitude, msLongitude, signaldBm);

                    Intent mapViewIntent = new Intent(this, HotSpotMapView.class);
                    mapViewIntent.putExtras(bundle);
                    startActivity(mapViewIntent);

                } catch (ActivityNotFoundException anfe) {
                    Log.d(TAG, anfe.getMessage());
                }
            }

            break;
        case R.id.btn_show_readings:
            Log.d(TAG, "Pressed show readings button");

            Bundle bundle = new Bundle(1);
            bundle.putInt("phoneType", phoneType);

            Intent bsListIntent = new Intent(this, HotSpotBSListActivity.class);
            bsListIntent.putExtras(bundle);
            startActivity(bsListIntent);

            break;
        case R.id.btn_delete_data:
            Log.d(TAG, "Deleting table data...");
            hotSpotAdapter.deleteData();
            break;
        case R.id.btn_populate_data:
            Log.d(TAG, "Populate test data...");
            hotSpotAdapter.populateTestData();
            break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (hotSpotAdapter != null) {
            hotSpotAdapter.close();
        }
    }

}
